from dataclasses import dataclass, field
import json
import traceback


@dataclass
class Bookmark:
    uid: int = -1
    name: str = ""
    value: str = ""
    tags: set[int] = field(default_factory=set)

    def to_dict(self):
        return {
            "uid": self.uid,
            "name": self.name,
            "value": self.value,
            "tags": list(self.tags),
        }

    @staticmethod
    def from_dict(dit):
        bmk = Bookmark()
        bmk.uid = dit["uid"]
        bmk.name = dit["name"]
        bmk.value = dit["value"]
        bmk.tags = set(dit["tags"])
        return bmk


EMPTY_BOOKMARK = Bookmark()

_max_id = 0
_bookmarks: dict[int, Bookmark] = dict()


def load(file_path):
    global _max_id, _bookmarks
    try:
        with open(file_path, "rb") as f:
            obj = json.load(f)
            _max_id = obj["max_id"]
            _bookmarks = dict()
            for dit in obj["bookmarks"]:
                bmk = Bookmark.from_dict(dit)
                _bookmarks[bmk.uid] = bmk
            return True
    except:
        traceback.print_exc()
        _max_id = 0
        _bookmarks = dict()
    return False


def save(file_path):
    try:
        with open(file_path, "wt", encoding="utf-8") as f:
            obj = {
                "max_id": _max_id,
                "bookmarks": [bmk.to_dict() for bmk in _bookmarks.values()]
            }
            json.dump(obj, f, indent=2)
    except:
        traceback.print_exc()

def add_bookmark(bmk: Bookmark):
    global _max_id
    if bmk.uid < 0:
        bmk.uid = _max_id
        _max_id += 1
        _bookmarks[bmk.uid] = bmk

def update_bookmark(bmk: Bookmark):
    if bmk.uid in _bookmarks:
        _bookmarks[bmk.uid] = bmk

def list_bookmarks():
    odlist = list(_bookmarks.values())
    odlist.sort(key=lambda item: item.uid)
    return odlist

def get_bookmark_by_name(name: str) -> Bookmark | None:
    for tag in _bookmarks.values():
        if tag.name == name:
            return tag
    return None

def get_bookmark_by_id(bmk_uid: int) -> Bookmark | None:
    if bmk_uid in _bookmarks:
        return _bookmarks[bmk_uid]
    return None

def delete_bookmark(bmk_uid: int):
    if bmk_uid in _bookmarks:
        del _bookmarks[bmk_uid]